package types

import (
	"fmt"
	"strings"
)

type ErrorCode int

const (
	ErrorCodeUnknown ErrorCode = iota
	ErrorCodeInternalServerError
	ErrorCodeRateLimited
	ErrorCodeNotFound
	ErrorCodeForbidden
	ErrorCodeBadRequest
	ErrorCodeUnauthorized
	ErrorCodeRpcError
	ErrorCodeWsError
	ErrorCodeThirdPartyFail
	ErrorCodeUnknownUser
	ErrorCodeShortLinkTaken
	ErrorCodeUnknownShortDomain
	ErrorCodeUnknownLibrary
	ErrorCodeTokenInvalid
	ErrorCodeUnknownResource
	ErrorCodeUnknownTag
	ErrorCodePermissionDenied
	ErrorCodeUnknownComment
	ErrorCodeUnknownBot
	ErrorCodeUnknownServer
	ErrorCodeUnknownBadge
	ErrorCodeUserAlreadyHasABadge
	ErrorCodeInvalidInviteCode
	ErrorCodeServerAlreadyExists
	ErrorCodeBotNotPresentOnQueueServer
	ErrorCodeUnknownUp
	ErrorCodeTooManyUps
	ErrorCodeInvalidStatus
	ErrorCodeUnknownReport
	ErrorCodeUnsupportedMediaType
	ErrorCodeUnknownApplication
	ErrorCodeAutomatedRequestsNotAllowed
	ErrorCodeInvalidRating
	ErrorCodeDuplicateBot
)

type Error struct {
	Code    ErrorCode `json:"code"`
	Message string    `json:"message"`
}

func (e Error) Error() string {
	return fmt.Sprintf("%d: %s", e.Code, e.Message)
}

type Errors []Error

func (e Errors) Error() string {
	errors := []string{}
	for _, err := range e {
		errors = append(errors, err.Error())
	}

	return strings.Join(errors, "\n")
}

type Response[T any] struct {
	Result  *T     `json:"result,omitempty"`
	Errors  Errors `json:"errors,omitempty"`
	Ok      bool   `json:"ok"`
	Service string `json:"service"`
}

func (r Response[T]) Error() string {
	if r.Ok {
		panic("response is ok, but the error was requested")
	}

	return r.Errors.Error()
}

func Ok[T any](data T) Response[T] {
	return Response[T]{
		Ok:      true,
		Errors:  Errors{},
		Result:  &data,
		Service: "notifications",
	}
}

func Err[T any](err ...Error) Response[T] {
	return Response[T]{
		Ok:      false,
		Errors:  err,
		Result:  nil,
		Service: "notifications",
	}
}

type ForceDisconnect struct {
	ID string `json:"id"`
}
